/**
 *   Copyright 2008 Alexey Vishentsev
 *
 *   Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 * 
 */

package com.gwtspreadsheetinput.gwt.client;


import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.FocusListener;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.KeyboardListener;
import com.google.gwt.user.client.ui.SourcesTableEvents;
import com.google.gwt.user.client.ui.TableListener;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;

public class InputManager extends AbsolutePanel {
	public TextBox editor;
	boolean editorVisible = false;
	private SelectionManager selectionManager;
    private Grid table;
    private int editingRow = -1;
    private int editingCol = -1;
    public DynamicGrid dynamicGrid;
	
	public InputManager() {
		//Init input panel
		addStyleName("spreadsheet-Input-container");
		setPixelSize(0, 0);
		DOM.setStyleAttribute(getElement(), "overflow", "visible");
		//Init input panel
		editor = new TextBox();
		editor.setStylePrimaryName("spreadsheet-Table-editor");
		editor.addKeyboardListener(new EditorKeyListener());
		editor.addFocusListener(new FocusListener(){
			public void onFocus(Widget sender) {
				editorFocusedCallback(true);
			}
			public void onLostFocus(Widget sender) {
				editorFocusedCallback(false);
			}});
		add(editor, -1000,-1000);
	}
	
	public boolean isEditing() {
		return editingRow >= 0;
	}
	
	public void startEditing(int row, int col) {
		if (isEditing()) {
			if (editingRow == row && editingCol == col) {
				return;
			}
			stopEditing(false);
		}
		editingRow = row;
		editingCol = col;
		updateEditorGeometry();
	}
	
	public void stopEditing(boolean commit) {
		if (!isEditing()) {
			return;
		}
		if (commit) {
			dynamicGrid.setCellText(editor.getText(), editingRow, editingCol);
			requestUpdateGeometry();
		}
		editingRow = -1;
		editingCol = -1;
		editor.setText("");
		//Problem with firefox 3.0.3
		DeferredCommand.addCommand(new Command(){
			public void execute() {
				editor.setText("");
			}
		});
		updateEditorGeometry();
	}
	
	public void updateEditorGeometry() {
		if (isEditing()) {
			int[] rect = new int[4];
			Util.getSelecitonRectangle(this.getElement().getParentElement(), 
					table, selectionManager.selectedRow, 
					selectionManager.selectedCol, rect);
			
			editor.setPixelSize(rect[2], rect[3]);
			setWidgetPosition(editor, rect[0], rect[1]);
		} else {
			setWidgetPosition(editor, -1000, -1000);
			editor.setPixelSize(200, 200);
		}
	}
	
	private void editCellContent() {
		String html = table.getHTML(selectionManager.selectedRow, selectionManager.selectedCol);
		html = html.replace("&nbsp;", "");
		html = html.replace("&lt;", "<");
		html = html.replace("&gt;", ">");
		editor.setText(html);
		editor.selectAll();
		startEditing(selectionManager.selectedRow, selectionManager.selectedCol);
	}
	
	public void setDynamicGrid(DynamicGrid dynamicGrid) {
		this.dynamicGrid = dynamicGrid;
		this.setTable(dynamicGrid.mainGrid);
		this.selectionManager = dynamicGrid.selectionManager;
		updateEditorGeometry();
	}
	
	public void setTable(Grid table) {
		this.table = table;
		this.table.addTableListener(new TableListener(){
			public void onCellClicked(SourcesTableEvents sender, int row,
					int cell) {
				cellClicked(row,cell);
			}});
	}
	
	private void cellClicked(int row, int col){
		if (isEditing()) {
			stopEditing(true);
		}
		selectionManager.setSelection(row, col);
	}
	
	
	private void requestUpdateGeometry(){
		dynamicGrid.requestUpdateGeometry();
	}
	
	private void editorFocusedCallback(boolean focused) {
		dynamicGrid.setComponentFocused(focused);
	}
	
	private class EditorKeyListener implements KeyboardListener{
		private boolean delOrBackSpaceEditInitiation = false;
		
		public boolean navigate(char keyCode, int modifiers){
			if (keyCode == KeyboardListener.KEY_TAB ) {
				return selectionManager.tabNavigation((modifiers & KeyboardListener.MODIFIER_SHIFT) != 0);
			} else if (keyCode == KeyboardListener.KEY_ENTER) {
				if (isEditing()) {
					stopEditing(true);
				} else {
					editCellContent();
				}
			} else if (keyCode == KeyboardListener.KEY_UP) {
				return selectionManager.upNavigation();
			} else if (keyCode == KeyboardListener.KEY_DOWN) {
				return selectionManager.downNavigation();
			} else if (keyCode == KeyboardListener.KEY_LEFT && !isEditing()) {
				return selectionManager.leftNavigation();
			} else if (keyCode == KeyboardListener.KEY_RIGHT && !isEditing()) {
				return selectionManager.rightNavigation();
			} else if (keyCode == KeyboardListener.KEY_ESCAPE && isEditing()) {
				stopEditing(false);
			} else if ((keyCode == KeyboardListener.KEY_DELETE || 
						keyCode == KeyboardListener.KEY_BACKSPACE) 
						&& !isEditing()) {
				delOrBackSpaceEditInitiation = true;
				editCellContent();
			}
			return false;
		}
		
		public void onKeyDown(Widget sender, char keyCode, int modifiers) {
			delOrBackSpaceEditInitiation = false;
			navigate(keyCode, modifiers);
			if (shouldCancelKey(keyCode)) {
				editor.cancelKey();
			}
		}

		public void onKeyPress(Widget sender, char keyCode, int modifiers) {
			if (shouldCancelKey(keyCode)) {
				editor.cancelKey();
			}
		}

		public void onKeyUp(Widget sender, char keyCode, int modifiers) {
			if (shouldCancelKey(keyCode)) {
				editor.cancelKey();
			}
			if (editor.getText().length() > 0 && !isEditing()) {
				startEditing(selectionManager.selectedRow, 
						selectionManager.selectedCol);
			}
		}
		
		private boolean shouldCancelKey(char keyCode){
			switch (keyCode) {
			case KEY_ENTER:
			case KEY_TAB:
			case KEY_ESCAPE:
				return true;
			case KEY_DELETE:
			case KEY_BACKSPACE:
				return delOrBackSpaceEditInitiation;
			default:
				break;
			}
			return false;
		}
		
	}
}
